import { ref, unref } from "vue";
import { uploadAlready, uploadChunk, mergeChunk } from "@/api";
import { fileToBuffer } from "@/utils";

export function useUploadLargeFile({ immediate = false } = {}) {
  // 上传文件框
  const inputRef = ref(null);
  const loading = ref(false);
  const filelist = ref([]); // 上次文件列表
  const progress = ref(0);

  // 选择文件
  const selectFile = () => {
    if (unref(loading)) return;
    unref(inputRef)?.click(); // 触发文件选择框
  };
  // 文件选中
  const changeFile = () => {
    let files = unref(inputRef)?.files[0];
    if (!unref(files)) return;
    filelist.value = files;
    if (immediate) {
      uploadFile();
    }
  };
  // 上传文件
  const uploadFile = async () => {
    if (unref(loading)) return alert("文件正在上传中");
    if (!unref(filelist)) return alert("请选择文件");
    loading.value = true; // 启动加载
    // 获取已经上传的切片信息
    let already = [];
    let { HASH, suffix, filename } = await fileToBuffer(unref(filelist)); // 大文件断点续传是一定要固定上传后文件名
    try {
      let data = await uploadAlready({ filename });
      if (data.exists) {
        progress.value = "100%";
        setTimeout(() => {
          alert("妙传成功");
          loading.value = false;
          progress.value = "";
        }, 500);
        return;
      }
      if (+data.code === 0) {
        already = data.fileList; // 获取到当前文件已经上传的片段名
      }
    } catch (err) {
      console.log(err.toString());
    }
    let file = filelist.value;
    // 实现文件切片处理 「固定数量 & 固定大小」 先根据最大切片优先如果切片数量太多则进行数量优先
    let fileMax = 1024 * 100; // 每个片段最大值
    let count = Math.ceil(file.size / fileMax); // 有多少切片数量
    let index = 0;
    let chunks = []; // 存放每个切片数据
    if (count > 100) {
      fileMax = file.size / 100;
      count = 100;
    }
    // 得到切片数据
    while (index < count) {
      chunks.push({
        file: file.slice(index * fileMax, (index + 1) * fileMax),
        filename: `${HASH}_${index + 1}.${suffix}`,
      });
      index++;
    }
    // 设置并发
    let beMax = 6; // 最大并发量(普遍浏览器支支持最大量)
    let taskTool = []; // 并发池子
    let i = 0;
    for (let chunk of chunks) {
      if (!already.includes(chunk.filename)) {
        let fm = new FormData();
        fm.append("file", chunk.file);
        fm.append("filename", chunk.filename);
        let task = uploadChunk(fm)
          .then((data) => {
            if (+data.code === 0) {
              taskTool.splice(
                taskTool.findIndex((item) => item === task), // 成功时移除并发池子
                1
              );
            } else {
              return Promise.reject(data.codeText);
            }
          })
          .catch(() => {
            console.log("当前切片上传失败，请您稍后再试~~");
          });
        // 并发池子达到最大数量时就等待请求完成再添加
        if (taskTool.length === beMax) {
          await Promise.race(taskTool);
        }
        taskTool.push(task);
      }
      i++;
      progress.value = `${(i / count) * 100}%`;
    }
    // 请求全部完成时
    Promise.all(taskTool)
      .then(async () => {
        try {
          // 进行合并操作请求
          const res = await mergeChunk({ HASH, count });
          if (+res.code === 0) {
            alert(
              `恭喜您，文件上传成功，您可以基于 ${res.servicePath} 访问该文件~~`
            );
          } else {
            throw res.codeText;
          }
        } catch (err) {
          alert("切片合并失败，请您稍后再试~~");
        }
      })
      .catch((err) => {
        console.log(err);
        alert("文件上传失败，请您稍后再试~~");
      })
      .finally(() => {
        loading.value = false;
        progress.value = "";
      });
  };

  return {
    inputRef,
    filelist,
    loading,
    progress,
    selectFile,
    changeFile,
  };
}
